#include "DM9000.h"
#include "2440addr.h"
#include "2440lib.h"
#include "raw_api.h"
#include "net_msg.h"
#include "uip.h"


#define DM9000_ADD (*((volatile unsigned short *) 0x20000300))

#define DM9000_CMD (*((volatile unsigned short *) 0x20000304))

#define Printf   Uart_Printf
#define HON(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

//uint8 mac_addr[6] = 	{0x11,0x22,0x33,0x44,0x55,0x66}; //开发板{ 0a,1b,2c,3d,4e,5f };

extern struct uip_eth_addr uip_ethaddr;



extern MEM_POOL MEM;
extern RAW_QUEUE driver_queue;

uint8 arpsendbuf[]={
	0xff,0xff,0xff,0xff,0xff,0xff,	//以太网目标地址
	0x11,0x22,0x33,0x44,0x55,0x66,	//以太网源地址
	0x08,0x06,						//帧类型：	ARP帧
	0x00,0x01,						//硬件类型：以太网
	0x08,0x00,						//协议类型：IP协议
	0x06,							//硬件地址长度：6字节
	0x04,							//协议地址长度：4字节
	0x00,0x01,						//操作： ARP请求
	0x11,0x22,0x33,0x44,0x55,0x66,	//发送端硬件地址
	192, 168, 1, 80,				    //发送端协议地址
	0x00,0x00,0x00,0x00,0x00,0x00,	//接收端硬件地址
	192, 168, 1, 100				//接收端协议地址
};


#define DM9000_ID	0x90000A46
#define DM9000_VID_L	0x28
#define DM9000_VID_H	0x29
#define DM9000_PID_L	0x2A
#define DM9000_PID_H	0x2B

//========================================================================================
void __udelay(uint32 t)
{
	#if 0
   U32 i;
   for(;t>0;t--)
   {
     for(i=0;i<100;i++){}
   }
   #endif
   
}
//==========================================================================================
void Test_DM9000AE()
{
	U32 id_val;
	rBWSCON = rBWSCON & ~(0xf<<16)|(0xd<<16);
	rBANKCON4 = (1 << 13)|(1<<11)|(6<<8)|(1<<6)|(1<<4)|(0<<2)|0;

	id_val = 0;
	DM9000_ADD = DM9000_VID_L;
	id_val = (uint8)DM9000_CMD;
	DM9000_ADD = DM9000_VID_H;
	id_val |= (uint8)DM9000_CMD<<8;
	DM9000_ADD = DM9000_PID_L;__udelay(2);
	id_val |= (uint8)DM9000_CMD<<16;
	DM9000_ADD = DM9000_PID_H;__udelay(2);
	id_val |= (uint8)DM9000_CMD<<24;
	Printf("DM9000AE ChipId is %x\r\n", id_val);
	if(id_val == DM9000_ID)
	{
		Printf("DM9000 ID correct\r\n");
	}
	else
	{
		Printf("DM9000 ID wrong\r\n");
	}
	
}



//=================================================================================================
//Eint7中断服务程序
 void Eint7_ISR(void)
{
	void *Buffer; 
	NET_MSG *msg; 

 	
	ClearPending(BIT_EINT4_7);
	rEINTPEND |= 1<<7; 

	if( RAW_SUCCESS == raw_block_allocate(&MEM,&Buffer) ){
	
		msg=(NET_MSG*)Buffer;
		msg->buffer=(unsigned char*)msg+sizeof(NET_MSG);
		msg->length =DM9000_receivepacket(msg->buffer);
	
		if(msg->length==0)
		raw_block_release(&MEM,Buffer);
		else
		{
		raw_queue_end_post(&driver_queue, msg); 
		
		}  
	}

}
//==================================================================================================
void DM9000_IOSetInit(void)
{
    	rGPFCON = (rGPFCON & (~(0x03<<14))) | (0x02<<14);
	       
	rEXTINT0 = (rEXTINT0 & (~(0x07<<28))) | (0x01<<28);
	rEINTPEND |=1<<7;
	rEINTMASK = rEINTMASK & (~(0x01<<7));         
	
	ClearPending(BIT_EINT4_7);             //BIT_EINT4_7 (0x1<<4)        
         
//	pISR_EINT4_7= (U32)Eint7_ISR; 
	
	register_irq(4, Eint7_ISR);
	rINTMSK = rINTMSK & (~(BIT_EINT4_7));
		
}
//===================================================================================================

void dm9000_reg_write(uint16 reg, uint16 data)
{  
//	__udelay(20);
	DM9000_ADD = reg;	
//	__udelay(20);
	DM9000_CMD = data;	
	
}
//===================================================================================================

uint8 dm9000_reg_read(uint16 reg)
{
//    __udelay(20);
    DM9000_ADD = reg;
//    __udelay(20);
    return DM9000_CMD;	
}
//===================================================================================================
uint16 dm9000_reg_read16(uint16 reg)
{
//    __udelay(20);
    DM9000_ADD = reg;
 //   __udelay(20);
    return DM9000_CMD;
}
//=================================================================================================
void DM9000_init(void)
{
	uint32 i;
	
	Test_DM9000AE();
	DM9000_IOSetInit();       
	Printf("in Dm9000 init\n");
	//初始化设置步骤: 1
	dm9000_reg_write(DM9000_GPCR, 0x01);	//设置GPCR(1EH) bit[0]=1，使DM9000的GPIO3为输出。
	dm9000_reg_write(DM9000_GPR,  0x00);	//GPR bit[0]=0 使DM9000的GPIO3输出为低以激活内部PHY。
	__udelay(5000);							//延时2ms以上等待PHY上电。
	
	//初始化设置步骤: 2
	dm9000_reg_write(DM9000_NCR,  0x03);	//软件复位
	__udelay(3000);							//延时20us以上等待软件复位完成
	dm9000_reg_write(DM9000_NCR,  0x00);	//复位完成，设置正常工作模式。
	dm9000_reg_write(DM9000_NCR,  0x03);	//第二次软件复位，为了确保软件复位完全成功。此步骤是必要的。
	__udelay(3000);
	dm9000_reg_write(DM9000_NCR,  0x00);    //以上完成了DM9000的复位操作
	
	

	dm9000_reg_write(DM9000_NSR,  0x2c);	//清除各种状态标志位
	dm9000_reg_write(DM9000_ISR,  0xbf);	//清除所有中断标志位

	

    dm9000_reg_write(DM9000_RCR,  0x39);	//接收控制
    dm9000_reg_write(DM9000_TCR,  0x00);	//发送控制
    dm9000_reg_write(DM9000_BPTR, 0x3f);
    dm9000_reg_write(DM9000_FCTR, 0x38);	//接收FIFO门限3k 8k
    dm9000_reg_write(DM9000_FCR,  0xff);
    dm9000_reg_write(DM9000_SMCR, 0x00);	

    

	for(i=0; i<6; i++)
		dm9000_reg_write(DM9000_PAR + i, uip_ethaddr.addr[i]);//mac_addr[]自己定义一下吧，6个字节的MAC地址
	

	dm9000_reg_write(DM9000_NSR,  0x2c);	//清除各种状态标志位
	dm9000_reg_write(DM9000_ISR,  0x3f);	//清除所有中断标志位

	dm9000_reg_write(DM9000_IMR, 0x81);		//中断使能	

	__udelay(10000);							//延时2ms以上等待PHY上电。

//	Printf("DM9000chu shi hua wan cheng\r\n");
}
//=====================================================================================

void DM9000_sendPcket(uint8 *datas, uint32 length)
{
	uint32 len,i;
	uint8 tmp;
	
	
	dm9000_reg_write(DM9000_IMR,0x80);		//先禁止网卡中断，防止在发送数据时被中断干扰	
	len = length;							//把发送长度写入
	
   dm9000_reg_write(DM9000_TXPLH, (len>>8) & 0x0ff);
    dm9000_reg_write(DM9000_TXPLL, len & 0x0ff);

	DM9000_ADD = DM9000_MWCMD;
	
	
    for(i=0; i<len; i+=2)					
    {
 //       __udelay(2);
        DM9000_CMD = datas[i] | (datas[i+1]<<8);
    }
 
	dm9000_reg_write(DM9000_TCR, 0x01);		//发送数据到以太网上

    while(1)
    {
    	uint8 data;
    	data = dm9000_reg_read(DM9000_TCR);//DM9000_NSR
    	if((data&0x01) == 0x00) break;
    }

    tmp = dm9000_reg_read(DM9000_NSR);
    
    if((tmp & 0x01) == 0x04)
    {
    	if((dm9000_reg_read(DM9000_TSR1)&0xfc) == 0x00)
    		;//Printf("TSR1成功\r\n");
    	else
    		;//Printf("TSR1失败r\n");   	
    }
    else
    {
    	if((dm9000_reg_read(DM9000_TSR2)&0xfc) == 0x00)
    		;//Printf("TSR2cheng gong \r\n");
    	else
    		;//Printf("TSR2shibai\r\n");
    }
    dm9000_reg_write(DM9000_NSR, 0x2c);		//清除状态寄存器，由于发送数据没有设置中断，因此不必处理中断标志位
    dm9000_reg_write(DM9000_IMR, 0x81);		//DM9000网卡的接收中断使能
	//Printf("fa song shu ju wan cheng\r\n");
}
//==============================================================================================
//接受数据包
//参数：datas为接收到是数据存储位置（以字节为单位）
//返回值：接收成功返回数据包类型，不成功返回0
uint32 DM9000_receivepacket(uint8 *datas)
{
	uint16 i,tmp,len;
	 volatile   uint16 status;
	uint8 ready;
	ready = 0;								//希望读取到"01H"
	status = 0;								//数据包状态

	len = 0; 								//数据包长度
	
    if(dm9000_reg_read(DM9000_ISR) & 0x01)			
    {
        dm9000_reg_write(DM9000_ISR, 0x01);	//清除接收中断标志位
    }
	
	ready = dm9000_reg_read(DM9000_MRCMDX); // 第一次读取，一般读取到的是 00H
	//Printf("ready1 = %x\r\n",ready);
	
   if((ready & 0x0ff) != 0x01)
    {
        ready = dm9000_reg_read(DM9000_MRCMDX); // 第二次读取，总能获取到数据
       // Printf("ready2 = %x\r\n",ready);
        if((ready & 0x01) != 0x01)
         {
           
            if((ready & 0x01) != 0x00) 		//若第二次读取到的不是 01H 或 00H ，则表示没有初始化成功
            {
		// Printf("in receive procket\n");
                 dm9000_reg_write(DM9000_IMR, 0x80);//屏蔽网卡中断
                 DM9000_init();				        //重新初始化
                
				  dm9000_reg_write(DM9000_IMR, 0x81);//打开网卡中断
            }
            return 0;            
         }   
    }
    
    status = dm9000_reg_read16(DM9000_MRCMD);
//    __udelay(20);
     len =DM9000_CMD;// DM9000_CMD;
    //Printf("in receive packet    receive  len  %d\n",len);

    if( (len < 1522))//!(status & 0xbf) &&
    {
        for(i=0; i<len; i+=2)// 16 bit mode
        {
//            __udelay(20);
            tmp = DM9000_CMD;
            datas[i] = tmp & 0x0ff;
            datas[i + 1] = (tmp >> 8) & 0x0ff;

	   // Printf("%x %x ",datas[i],datas[i+1]);
        }
    }
    else			return 0;
	if(len > 1000) 	return 0;
 /* if( (HON( ETHBUF->type ) != ETHTYPE_ARP) && (HON( ETHBUF->type ) != ETHTYPE_IP) )
		return 0;*/

	return len;
}

//============================================================================================
//打印DM9000的寄存器
void DM9000_PrintReg(void)
{
	uint16 data,i;
	for(i=0x0;i<0x10;i++)
	{
		data = dm9000_reg_read(i);
		Printf("RET_0x%02x = %x\r\n",i,data);
	}
	Printf("\r\n");
	for(i=0x10;i<0x16;i++)
	{
		data = dm9000_reg_read(i);
		Printf("RET_0x%02x = %02x\r\n",i,data);
	}
	
	i=0x16;
	data = dm9000_reg_read(i);
	Printf("RET_0x%2x = %x\r\n",i,data);
	
	for(i=0x1e;i<0x26;i++)
	{
		data = dm9000_reg_read(i);
		Printf("RET_0x%2x = %x\r\n",i,data);
	}
	
	for(i=0x28;i<0x2c;i++)
	{
		data = dm9000_reg_read(i);
		Printf("RET_0x%2x = 0x%x\r\n",i,data);
	}
	
	i=0x2f;
	data = dm9000_reg_read(i);
	Printf("RET_0x%2x = %x\r\n",i,data);
	
	for(i=0xf0;i<0xff;i++)
	{
		data = dm9000_reg_read(i);
		Printf("RET_0x%2x = %x\r\n",i,data);
	}
	data = dm9000_reg_read(i);
	Printf("RET_0x%2x = %x\r\n",i,data);
	
	data = dm9000_reg_read(0xfe);
	Printf("chu li qi IO mo shi:%x\r\n",((uint8)data)>>6);
	
	data = dm9000_reg_read(0x01);
	if(((uint8)data)>>1)
		Printf("10M yi tai wang\r\n");				
	else
		Printf("100Myi tai wang\r\n");
	
	data = dm9000_reg_read(0x02);
	//Printf("TCR（02H）：fa song kong zhi ji cun qi :%x\r\n",((uint8)data));
	
	//TestDm9000();
}
//===========================================================================================
//Dm9000的测试

void Dm9000_Test(void)
{
	DM9000_sendPcket(arpsendbuf,42);
	//arp_request();
}


